const path = require("path"); // nodeJs 的 path 模块
const HtmlWebpackPlugin = require("html-webpack-plugin"); // 生成html的插件，并自动将打包后的 JS、CSS 文件引入 HTML 文件中
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 将css代码从js文件中拆分出来
const EslintPlugin = require("eslint-webpack-plugin"); // eslint 代码校验插件
const WebpackSpritesmith = require("webpack-spritesmith"); // 生成雪碧图插件

module.exports = {
  mode: "development", // 模式为开发模式
  devtool: false, // 不生成sourcemap
  entry: "./src/index.js", // entry：默认的路径是src/index.js，也可以自定义
  output: {
    path: path.resolve(__dirname, "dist"), // 打包文件的输出位置
    filename: "main.js", // 打包后的文件名
    clean: true, // 在新的打包之前清除历史文件
  },
  devServer: {
    static: path.join(__dirname, "public"), // 静态资源路径
    compress: true, // 是否开始gzip压缩
    host: "localhost", // 服务器主机名
    port: 80, // 服务器端口名
    open: true, //启动项目后是否自动打开浏览器
    hot: true, // 是否启动模块热替功能
    historyApiFallback: true, // 处理单页应用的路由问题
    watchFiles: ["src/**/*.js", "src/**/*.css"], // 需要监听的文件列表，当这些文件发生变化时，自动重启服务器
  },
  module: {
    rules: [
      {
        test: /\.png$/,
        type: "asset/resource",
      },
      {
        test: /\.jpg$/,
        type: "asset/inline",
      },
      {
        test: /\.bmp$/,
        type: "asset/source",
      },
      {
        test: /\.svg$/,
        type: "asset",
        parser: {
          dataUrlCondition: {
            maxSize: 2048, // 大于maxSize的"asset/resource"，小于maxSize的"asset/inline"
          },
        },
      },
      {
        // 匹配文件的正则表达式，这里表示匹配JPG、PNG、GIF和SVG格式的图片文件
        test: /\.(jpe?g|png|gif|svg)$/i,
        use: [
          {
            // 使用image-webpack-loader对图片进行优化和压缩
            loader: "image-webpack-loader",
            options: {
              // 是否禁用图片优化和压缩
              disable: process.env.NODE_ENV === "development",
              mozjpeg: {
                progressive: true, // 是否开启渐进式JPEG，可以有效提升JPEG图片加载速度
                quality: 65, // 压缩JPEG图片的质量，取值范围为0到100，值越大质量越好但文件越大
              },
              optipng: {
                enabled: true, // 是否开启PNG图片的优化，可以有效提升PNG图片加载速度
              },
              pngquant: {
                // 压缩PNG图片的质量范围，取值范围为0到1，值越大质量越好但文件越大
                // 第一个数字表示压缩质量的下限，第二个数字表示压缩质量的上限
                quality: [0.65, 0.9],
                speed: 4, // 压缩PNG图片的速度，取值范围为1到10，值越大速度越快但质量越低
              },
              svgo: {
                plugins: [
                  // 压缩SVG图片的插件列表，这里包含removeViewBox和cleanupIDs两个插件
                  {
                    //用于删除SVG图片中的viewBox属性
                    //viewBox属性是用来指定SVG视口范围的，它的值是一个矩形框的坐标和宽高
                    removeViewBox: false,
                  },
                  {
                    //用于删除SVG图片中的无用ID属性
                    cleanupIDs: true,
                  },
                ],
              },
              gifsicle: {
                interlaced: true, // 是否开启GIF图片的隔行扫描,可以有效提升GIF图片加载速度
              },
            },
          },
        ],
      },
      {
        test: /\.png$/,
        //oneOf是一个优化选项，用于提高打包的速度
        oneOf: [
          {
            //resourceQuery是一个用于匹配请求资源的URL中查询字符中是否包含sizes，如果包含则切图，不包含则执行下面的asset/resource
            resourceQuery: /sizes/,
            use: [
              {
                loader: "responsive-loader",
                options: {
                  adapter: require("responsive-loader/sharp"),
                },
              },
            ],
          },
          {
            type: "asset/resource",
          },
        ],
      },
      {
        test: /\.ts$/, // 匹配以 .ts 结尾的文件
        // use: ["ts-loader"], // 由于ts-loader存在一定的性能问题，因此这里我们可以配置 @babel/preset-typescript 来转换ts代码
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-typescript"],
            },
          },
        ],
        exclude: /node_modules/, // 不匹配的文件。排除 node_modules 文件夹，不进行 ts 转换
      },
      {
        test: /\.js$/, // 匹配以 .js 结尾的文件
        use: [
          {
            loader: "babel-loader",
            // options: { // 可以直接在这里配置预设，也可以在 .babelrc 文件中配置，也可以在babel.config.js 中配置
            //	 presets: ["@babel/preset-env"]
            // }
          },
        ],
      },
      {
        test: /\.css$/, // 匹配以 .css 结尾的文件
        use: [
          process.env.NODE_ENV === "development"
            ? "style-loader"
            : MiniCssExtractPlugin.loader,
          "css-loader",
          "postcss-loader",
        ], // 注意：loader执行顺序是从后往前执行，顺序不能改变
      },
      {
        test: /\.less$/, // 匹配以 .less 结尾的文件
        use: [
          process.env.NODE_ENV === "development"
            ? "style-loader"
            : MiniCssExtractPlugin.loader,
          "css-loader",
          "postcss-loader",
          // "less-loader",
          {
            loader: "less-loader",
            options: {
              lessOptions: {
                paths: [path.resolve(__dirname, "src/sprite")],
              },
            },
          },
        ],
      },
      {
        test: /\.scss$/, // 匹配以 .scss 结尾的文件
        use: [
          process.env.NODE_ENV === "development"
            ? "style-loader"
            : MiniCssExtractPlugin.loader,
          "css-loader",
          "postcss-loader",
          "sass-loader",
        ],
      },
    ],
  },
  plugins: [
    // 插件使用时，像构造函数一样直接 new 即可
    // template：模板文件的路径
    // filename：打包后生成的文件名
    // chunk：代码块
    new HtmlWebpackPlugin({ template: "./src/index.html" }),
    new MiniCssExtractPlugin(),
    new EslintPlugin({
      extensions: ["js", "jsx", "ts", "tsx"], // 这些类型的文件需要进行 eslint 代码检查
    }),
    new WebpackSpritesmith({
      // 具体配置可查看github
      src: {
        //指定输入的文件
        cwd: path.resolve(__dirname, "src/images/icons"),
        glob: "**/*.png",
      },
      target: {
        //指定输出的文件路径
        image: path.resolve(__dirname, "src/sprite/sprite.png"),
        css: path.resolve(__dirname, "src/sprite/sprite.less"),
      },
      apiOptions: {
        // 指定CSS文件应使用相对路径引用精灵图
        cssImageRef: "sprite/sprite.png",
      },
      spritesmithOptions: {
        algorithm: "top-down",
        padding: 10,
      },
    }),
  ],
};
